QuickOPC User's Guide and Reference
Examples - OPC XML-DA - Browse nodes recursively
// This example shows how to recursively browse the nodes in the OPC XML-DA address space.

using System;
using System.Diagnostics;
using OpcLabs.EasyOpc;
using OpcLabs.EasyOpc.DataAccess;
using OpcLabs.EasyOpc.DataAccess.AddressSpace;
using OpcLabs.EasyOpc.OperationModel;

namespace DocExamples.DataAccess.Xml
{
    class BrowseNodes
    {
        public static void RecursiveXml()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();

            // Instantiate the client object.
            var client = new EasyDAClient();

            _branchCount = 0;
            _leafCount = 0;

            try
            {
                BrowseFromNode(client, "http://opcxml.demo-this.com/XmlDaSampleServer/Service.asmx", "");
            }
            catch (OpcException opcException)
            {
                Console.WriteLine("*** Failure: {0}", opcException.GetBaseException().Message);
                return;
            }

            stopwatch.Stop();
            Console.WriteLine("Browsing has taken (milliseconds): {0}", stopwatch.ElapsedMilliseconds);
            Console.WriteLine("Branch count: {0}", _branchCount);
            Console.WriteLine("Leaf count: {0}", _leafCount);
        }

        private static void BrowseFromNode(
            EasyDAClient client,
            ServerDescriptor serverDescriptor,
            DANodeDescriptor parentNodeDescriptor)
        {
            Debug.Assert(client != null);
            Debug.Assert(serverDescriptor != null);
            Debug.Assert(parentNodeDescriptor != null);

            // Obtain all node elements under parentNodeDescriptor
            var browseParameters = new DABrowseParameters();    // no filtering whatsoever
            DANodeElementCollection nodeElementCollection =
                client.BrowseNodes(serverDescriptor, parentNodeDescriptor, browseParameters);
            // Remark: that BrowseNodes(...) may also throw OpcException; a production code should contain handling for 
            // it, here omitted for brevity.

            foreach (DANodeElement nodeElement in nodeElementCollection)
            {
                Debug.Assert(nodeElement != null);

                Console.WriteLine(nodeElement);

                // If the node is a branch, browse recursively into it.
                if (nodeElement.IsBranch)
                {
                    _branchCount++;
                    BrowseFromNode(client, serverDescriptor, nodeElement);
                }
                else
                {
                    _leafCount++;
                }
            }
        }

        private static int _branchCount;
        private static int _leafCount;
    }
}
# This example shows how to recursively browse the nodes in the OPC XML-DA address space.

# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc
import timeit

# Import .NET namespaces.
from OpcLabs.EasyOpc import *
from OpcLabs.EasyOpc.DataAccess import *
from OpcLabs.EasyOpc.OperationModel import *


def browseFromNode(client, serverDescriptor, parentNodeDescriptor):
    global branchCount
    global leafCount

    assert client is not None
    assert serverDescriptor is not None
    assert parentNodeDescriptor is not None

    # Obtain all node elements under parentNodeDescriptor.
    browseParameters = DABrowseParameters() # no filtering whatsoever
    nodeElementCollection = client.BrowseNodes(serverDescriptor, parentNodeDescriptor, browseParameters)
    # BrowseNodes(...) may also throw OpcException; here it is handled by the caller.

    for nodeElement in nodeElementCollection:
        assert nodeElement is not None
        print(nodeElement)

        # If the node is a branch, browse recursively into it.
        if nodeElement.IsBranch:
            branchCount = branchCount + 1
            browseFromNode(client, serverDescriptor, DANodeDescriptor(nodeElement))
        else:
            leafCount = leafCount + 1


beginTime = timeit.default_timer()

# Instantiate the client object.
client = EasyDAClient()
branchCount = 0
leafCount = 0

try:
    browseFromNode(client,
                   ServerDescriptor('http://opcxml.demo-this.com/XmlDaSampleServer/Service.asmx'),
                   DANodeDescriptor(''))
except OpcException as opcException:
    print('*** Failure: ' + opcException.GetBaseException().Message)
    exit()

endTime = timeit.default_timer()
print()
print('Browsing has taken (milliseconds): ',(endTime - beginTime)*1000)
print('Branch count: ', branchCount);
print('Leaf count: ', leafCount);
' This example shows how to recursively browse the nodes in the OPC XML-DA address space.

Imports OpcLabs.EasyOpc
Imports OpcLabs.EasyOpc.DataAccess
Imports OpcLabs.EasyOpc.DataAccess.AddressSpace
Imports OpcLabs.EasyOpc.OperationModel

Namespace DataAccess.Xml
    Partial Friend Class BrowseNodes

        Shared Sub RecursiveXml()
            Dim stopwatch = New Stopwatch()
            stopwatch.Start()

            Dim client = New EasyDAClient()
            _branchCount = 0
            _leafCount = 0

            Try
                BrowseFromNode(client, "http://opcxml.demo-this.com/XmlDaSampleServer/Service.asmx", "")
            Catch opcException As OpcException
                Console.WriteLine("*** Failure: {0}", opcException.GetBaseException().Message)
                Exit Sub
            End Try

            stopwatch.Stop()
            Console.WriteLine("Browsing has taken (milliseconds): {0}", stopwatch.ElapsedMilliseconds)
            Console.WriteLine("Branch count: {0}", _branchCount)
            Console.WriteLine("Leaf count: {0}", _leafCount)
        End Sub

        Private Shared Sub BrowseFromNode( _
            client As EasyDAClient,
            serverDescriptor As ServerDescriptor,
            parentNodeDescriptor As DANodeDescriptor)

            Debug.Assert(client IsNot Nothing)
            Debug.Assert(serverDescriptor IsNot Nothing)
            Debug.Assert(parentNodeDescriptor IsNot Nothing)

            ' Obtain all node elements under parentNodeDescriptor
            Dim browseParameters = New DABrowseParameters() ' no filtering whatsoever
            Dim nodeElementCollection As DANodeElementCollection =
                client.BrowseNodes(serverDescriptor, parentNodeDescriptor, browseParameters)
            ' Remark: that BrowseNodes(...) may also throw OpcException; a production code should contain handling for 
            ' it, here omitted for brevity.

            For Each nodeElement As DANodeElement In nodeElementCollection
                Debug.Assert(nodeElement IsNot Nothing)

                Console.WriteLine(nodeElement)

                ' If the node is a branch, browse recursively into it.
                If nodeElement.IsBranch Then
                    _branchCount += 1
                    BrowseFromNode(client, serverDescriptor, nodeElement)
                Else
                    _leafCount += 1
                End If
            Next nodeElement
        End Sub

        Private Shared _branchCount As Integer
        Private Shared _leafCount As Integer
    End Class
End Namespace
QuickOPC supports OPC XML-DA also on Linux and macOS.
See Also

Examples - OPC Data Access

Conceptual